大家有沒有想過當你在終端機輸入指令時,電腦是如何理解並執行這些指令的?或者當你使用正則表達式搜尋文字時,背後的機制是什麼?這些看似神奇的功能背後,其實都隱藏著一個強大而優雅的設計模式,那就是解釋器模式 Interpreter Pattern,今天就來聊聊這個模式,幫助我們理解當電腦「讀懂」我們的指令時背後的魔法。
解釋器模式是一種行為型設計模式,主要用來解析語言、處理簡單語法規則的。這個模式背後的想法其實很簡單:我們定義一套「語法規則」,然後讓每個「字元」或「符號」有自己專屬的解釋方式。這樣我們就能依照語法,逐步分析出我們想要的結果。
打個比方,就像我們學習一種新語言時,會先學習單字,接著組合句子,最後可以用來進行溝通。解釋器模式就像是這個過程的數位版,先定義每個「單字」的意思,再教你如何解釋這些字。
計算機應該是最能體現解釋器模式的例子之一。想像你有一個簡單的計算機,輸入表達式如「2 + 3 * 4」,然後計算出結果。解釋器模式就可以幫助我們將這些數字與運算符號組合成一個能夠「理解」的語法樹。
首先先定義一個 Expression
介面,它會有一個 interpret()
方法。這個方法負責對數字和符號進行解釋,
// 抽象表達式
class Expression {
public:
virtual int interpret() = 0;
virtual ~Expression() = default;
};
接著定義具體的 NumberExpression
(數字表達式)和 OperatorExpression
(運算符表達式)。數字表達式會簡單地回傳它自己的值,而運算符表達式則會對兩個子表達式進行計算,比如加法、乘法等。
// 數字表達式
class NumberExpression : public Expression {
int number;
public:
NumberExpression(int num) : number(num) {}
int interpret() override {
return number;
}
};
// 加法表達式
class AddExpression : public Expression {
Expression* left;
Expression* right;
public:
AddExpression(Expression* l, Expression* r) : left(l), right(r) {}
int interpret() override {
return left->interpret() + right->interpret();
}
};
// 乘法表達式
class MultiplyExpression : public Expression {
Expression* left;
Expression* right;
public:
MultiplyExpression(Expression* l, Expression* r) : left(l), right(r) {}
int interpret() override {
return left->interpret() * right->interpret();
}
};
在前面已經定義了基礎的 NumberExpression、AddExpression 和 MultiplyExpression 類別。接下來我們在客戶端來實際使用這些表達式,讓整個流程完整起來。
我們會有一個解析器來遍歷表達式,並一步步解釋每個部分。假設我們要處理一個簡單的表達式「2 + 3」,客戶端的邏輯會像下面這樣:
int main() {
// 建立一個表示數字2的NumberExpression
Expression* num1 = new NumberExpression(2);
// 建立一個表示數字3的NumberExpression
Expression* num2 = new NumberExpression(3);
// 建立一個表示加法的AddExpression,將兩個數字作為參數傳入
Expression* addExpr = new AddExpression(num1, num2);
int result = addExpr->interpret();
std::cout << "2 + 3 = " << result << std::endl;
Expression* mulExpr = new MultiplyExpression(num1, num2);
result = mulExpr->interpret();
std::cout << "2 * 3 = " << result << std::endl;
// 釋放記憶體
delete num1;
delete num2;
delete addExpr;
delete mulExpr;
return 0;
}
執行上述程式碼,我們會得到以下輸出,當我們將表達式「2 + 3」傳給計算機時,解釋器就會根據我們定義的語法規則一步步處理,最終給出結果。
2 + 3 = 5
2 * 3 = 6
在這個範例中,客戶端的角色就是負責將表達式拼接在一起,然後使用解釋器模式的物件來完成運算。這樣任何新加入的運算符或表達式,只需要擴展 Expression 類別,而不用改動客戶端的邏輯,保持程式的靈活性和可維護性。
說到解釋器模式的優點,它最大的魅力就在於可以輕鬆地擴展和修改語法規則。比如我們可以在不改變原有架構的情況下,輕鬆加入新的運算符號或功能,這讓解釋器模式在處理語法解析時非常靈活。
解釋器模式的缺點也很明顯。當語法規則變得越來越複雜時,類別的數量會激增,這可能導致程式碼的維護和理解變得困難。另外解釋器模式的效能並不高,尤其是當處理大規模語法時,效能的瓶頸會更加明顯。
解釋器模式就像一個小型語法解析器,適合用來處理簡單的語法規則,像是計算機這樣的場景。它的擴展性讓我們可以在程式中輕鬆加入更多規則,但同時也要留意其效能和維護性。對於那些需要頻繁變更規則、處理複雜語法的情況,解釋器模式提供了一個簡潔且靈活的解決方案。
更多C++語言相關的文章,歡迎追蹤我的部落格。
https://shengyu7697.github.io/cpp-interpreter-pattern/